/**
 * Created by huangzx on 2015/7/28.
 */
define('framework/groupgrid/GillionGroupGridModule', [
    'angular',
    'framework/datasource/DataSourceModule'
], function (angular) {

    //去除空格
    function trim(st){
        var re = /^\s+|\s+$/g;
        return st.replace(re, "");
    };

    function toArray(source, desc) {
        angular.forEach(source, function (record) {
            desc.push(cloneButChildren(record));
            if (record.hasOwnProperty('children')) {
                toArray(record.children, desc);
            }
        });
    }

    function cloneButChildren(source) {
        var result = {};
        angular.forEach(source, function (v, k) {
            if (k !== 'children') {
                result[k] = v;
            }
        });
        return result;
    }

    function groupByProp(source, props, level) {
        var prop = props[0],
            extraProps = props.slice(1),
            hasExtraProps = extraProps.length > 0,
            groupedObj = {},
            result = [],
            index = 0;
        angular.forEach(source, function (v) {
            var propVal = v[prop];
            if (!groupedObj.hasOwnProperty(propVal)) {
                groupedObj[propVal] = [];
            }
            groupedObj[propVal].push(v);
        });

        level = level || '';
        angular.forEach(groupedObj, function (v, k) {
            index++;
            var item = {};
            item[prop] = k;
            item.$groupField = prop;
            item.$visualField = level + '' + index;
            if (hasExtraProps) {
                item.children = groupByProp(v, extraProps, item.$visualField);
            }else {
                item.children = v;
                item.$lastGroupField = true;
                angular.forEach(item.children,function(v){
                    v.$visualField = item.$visualField;
                });
            }
            result.push(item);
        });
        return result;
    }

    return angular.module('GillionGroupGridModule', ['DataSourceModule']).
        directive('gGroupGrid', function ($parse, Arrays, $dataSourceManager) {
            function GroupGrid(scope){
                this.scope = scope;
                this.columns = scope.columns  = [];
                this.rows = scope.rows = [];
                this.cellValueGetterCache = [];
            }

            GroupGrid.prototype.addColumn = function(column){
                this.columns.push(column);
            };

            GroupGrid.prototype.selectedRow = function(rowIndex){
                return this.scope.rows[rowIndex];
            };

            GroupGrid.prototype.getCellValue = function (row, column) {
                var me = this,
                    cellValueGetterCache = me.cellValueGetterCache;
                if (!cellValueGetterCache[column.data]) {
                    cellValueGetterCache[column.data] = me.generateCellValueGetter(column);
                }
                return cellValueGetterCache[column.data](row);
            };

            GroupGrid.prototype.generateCellValueGetter = function (column) {
                if (column.data) {
                    return $parse(column.data);
                }
                return angular.noop;
            };

            return {
                restrict: 'E',
                template: '<div class="group-table">\n    <table class="com-table" width="100%" border="0" cellspacing="0" cellpadding="0">\n        <thead>\n            <tr>\n            </tr>\n        </thead>\n        <tbody>\n            <tr g-group-tr ng-repeat="(rowIndex, row) in rows" data-row-index="{{rowIndex}}" data-code="{{row.$visualField}}"\n                ng-class="{\'group-table-inner\': !row.$groupField, \'group-table-title\': row.$groupField}">\n            </tr>\n        </tbody>\n    </table>\n</div>',
                replace: true,
                transclude: true,
                require: 'gGroupGrid',
                scope: {
                    sourceName: '@',
                    groupFields: '@',
                    onSelect: '&'
                },
                compile: function (tEle, tAttrs, transclude) {
                    var $head = tEle.find('thead tr');
                    return function (scope, ele, attrs, gGroupGrid) {
                        scope.$on(scope.sourceName, function (context,dataSource) {
                            toArray(groupByProp(dataSource.records, scope.groupFields.split(',')), scope.rows);
                        });

                        $dataSourceManager.getDataSource(scope.sourceName).then(function (result) {
                            result.doRequestData();
                        });

                        transclude(scope, function (clone) {
                            angular.forEach(clone, function(obj){
                                if (obj.tagName === 'TH') {
                                    $head.append(obj);
                                }
                            })
                        }, gGroupGrid);

                        //折叠展开分组事件
                        ele.on('click', '.table-down-icon', function(){
                            var $this = angular.element(this),
                                $tr = $this.parent().parent().parent();
                            $this.toggleClass('icon-xiangxia icon-zhankai').toggleClass('icon-xiangshang icon-shouqi');
                            if ($this.hasClass('icon-zhankai')) {
                                $tr.nextAll('tr[data-code^="' + $tr.data('code') + '"]').hide();
                                if (!$this.data('last-title')) {
                                    $tr.nextAll('tr[data-code^="' + $tr.data('code') + '"]').filter(function(){
                                        return angular.element(this).hasClass('group-table-title');
                                    }).find('.table-down-icon').addClass('icon-xiangxia icon-zhankai').removeClass('icon-xiangshang icon-shouqi');
                                }
                            } else {
                                if ($this.data('last-title')) {
                                    $tr.nextAll('tr[data-code^="' + $tr.data('code') + '"]').show();
                                } else {
                                    $tr.nextAll('tr[data-code^="' + $tr.data('code') + '"]').filter(function(){
                                        return angular.element(this).hasClass('group-table-title');
                                    }).show();
                                }
                            }
                        }).on('click', '.group-table-inner', function(){
                            var $currRow = angular.element(this);
                            $currRow.toggleClass('on').siblings().removeClass('on');

                            //回调选中某条记录
                            scope.onSelect({
                                record: gGroupGrid.selectedRow($currRow.data('row-index'))
                            });
                        });
                    };
                },
                controller: function($scope){
                    return new GroupGrid($scope);
                }
            }
        }).
        directive('gGroupColoum', function () {
            return {
                restrict: 'E',
                replace: true,
                transclude: true,
                template: '<th style="text-align:{{hAlign}};width:{{width}}" ng-transclude></th>',
                scope:{
                    field: '@',
                    width: '@',
                    hAlign: '@',
                    align: '@'
                },
                require: '^gGroupGrid',
                link: function(scope, ele, attrs, gGroupGrid) {
                    var column = {
                        title: ele.text(),
                        field: trim(scope.field.split('|')[0]),
                        data:scope.field,
                        width: scope.width,
                        hAlign: scope.hAlign,
                        align: scope.align
                    };
                    gGroupGrid.addColumn(column);
                }
            }
        }).
        directive('gGroupTr', function($compile){
            return {
                restrict: 'A',
                require: '^gGroupGrid',
                link: function(scope, ele, attrs, gGroupGrid){
                    var tplTitle = '<td ng-repeat="column in columns" style="text-align: {{column.align}}">\n    <span>\n        <i ng-if="column.field==row.$groupField" data-last-title="{{row.$lastGroupField}}" class="table-down-icon iconfont icon-xiangshang icon-shouqi"></i>\n        <span ng-if="column.field==row.$groupField" g-group-cell></span>\n    </span>\n</td>',
                        tplInner = '<td g-group-cell ng-repeat="column in columns" style="text-align: {{column.align}}"><span></span></td>',
                        tpl;
                    if (scope.row.$groupField){
                        tpl = $compile(tplTitle)(scope)
                    } else {
                        tpl = $compile(tplInner)(scope)
                    }
                    ele.append(tpl);
                }
            };
        }).
        directive('gGroupCell', function ($compile) {
            return {
                restrict: 'A',
                require: '^gGroupGrid',
                link: function (scope, ele, attrs, gGroupGrid) {
                    var row = scope.row,
                        column = scope.column,
                        html;
                    html = gGroupGrid.getCellValue(row, column);
                    ele.html(html);
                }
            };
        })
        ;
});